package com.example.kotlindemo.flow.FLowTest

import android.util.Log
import androidx.compose.ui.tooling.data.EmptyGroup
import androidx.compose.ui.tooling.data.EmptyGroup.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.channels.produce
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.retry
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext


fun test(){
    GlobalScope.launch {
        val withStr = withContext(Dispatchers.Default){
            "a"
        }

        val awaitby = async{
            "b"
        }

        Log.d("luge","$awaitby")
        Log.d("luge", withStr)

        simple().forEach {
            value ->
            Log.d("luge","$value")
        }
    }
}

private fun simple():Sequence<Int> = sequence {
    for (i in 1..3){
        Thread.sleep(100)
        yield(i)
    }

//    //flow 的方式
//    flow<Int> {
//        for(i in 1..3){
//            delay(100)
//            emit(i)
//        }
//    }.collect{
//        value ->
//        println(value)
//    }
//
}

fun test4(){
    runBlocking {
        (1..4).asFlow().collect{
            println()
        }

//        flowOf(1,2,3,4).collect(

            flow<Int> {
        for(i in 1..3){
            delay(100)
//            emit(i)
            if(i == 2){
                withContext(Dispatchers.IO){
                    emit(i);
                }
            }
        }
    }.collect{
        value ->
        println(value)
    }
    }
}


fun test5(){
    runBlocking {
        flow {
            for (i in 1..3){
                print("${currentCoroutineContext()}")
                emit(i)
            }
        }.flowOn(Dispatchers.IO).map {
            //todo 数据处理
        }.flowOn(Dispatchers.Main).map {
            //todo 数据处理
        }.collect {
            print("${currentCoroutineContext()}")
        }
    }

}


public fun <T> Array<T>.asFlow(): Flow<T> = flow {
    forEach { value ->
        emit(value)
    }
}



fun test6(){
    runBlocking {
        flow {
            for (i in 1..3){
                print("${currentCoroutineContext()}")
                emit(i)
            }
        }.map {
            it * 5
        }.map {
            it * 100
        }.mapNotNull {
            it
        }
        var data =  (1..2).asFlow()
        data = (100..400).asFlow()


        }



//        flowOf("1","2",null,10)
//            .retry(2).catch { emit(110) }
//            .filterIsInstance<String>().collect{}

        //组合
        val nameFlow = mutableListOf<String>("1","2").asFlow()
        val numFlow = mutableListOf<Int>(1,2).asFlow()

        nameFlow.zip(numFlow){  //"1":1 "2":2   “1” “2” 1 2
            string,num ->
            "$string:$num"
        }

        merge(nameFlow,numFlow)



    }

}


fun test2(){
    runBlocking {
        var flow = (1..4).asFlow()
        flow.collect{
            println("$it")
        }
        flow = (5..7).asFlow()
        flow.collect{
            println("$it")
        }
    }
}

fun test3(){
    runBlocking {
        val channel = Channel<Int>()
        launch {
            for (x in 1..8) channel.send(x)
            channel.close()
        }
        launch {
            delay(1000)
            channel.send(9999)
            channel.send(8888)
        }
        repeat(Int.MAX_VALUE){
            println("${channel.receive()}")
        }
        println("done")
    }
}



fun test10(){
    runBlocking {
        val channel = Channel<Int>()
        launch {
        if(!channel.isClosedForSend) {
            for (x in 1..9) channel.send(x)
            channel.close()
        }
        }
        launch {
           delay(1000)
            channel.send(999)
            channel.send(888)
        }
        repeat(Int.MAX_VALUE){
            println("${channel.receive()}")
        }
        println("ok")


        /////////

        val produceTest = produceTest()
        produceTest.consumeEach {
            print("$it")
        }
    }
}


private fun CoroutineScope.produceTest():ReceiveChannel<Int> = produce{
    for( x in 1..100)
        send(x)
}

fun main() {
//    test()
//    test2()
    test5()
}